package com.cvtt.voice;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

import android.content.Context;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.media.ToneGenerator;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.PowerManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;


import com.cvtt.common.Util;
import com.cvtt.sip.SIPConfig;
import com.cvtt.sip.SIPEngine;
import com.cvtt.voice.codec.Codecs;
import com.cvtt.voice.gips.GIPSVoice;
import com.cvtt.voice.simple.RTPStreamReceiver;
import com.cvtt.voice.simple.SimpleVoice;
import com.cvtt.voice.tools.VoiceUtil;

public class VoiceEngine {

	private static final String LOG_TAG = "VoiceEngine";
	public final static int VOICE_SIMPLE = 0;
	public final static int VOICE_GIPS = 1;
	public final static int VOICE_SPEEX = 2;

	public static int voiceMode;

	private boolean bStart;

	private GIPSVoice gipsVoice = null;
	private SimpleVoice simpleVoice = null;

	private boolean bPlayout = true;

	private boolean adjustVolume = false;

	private int nCurVolume;

	private AudioManager audioManager;

	private ToneGenerator toneGenerator;
	private ToneGenerator ringbackPlayer;

	private MediaPlayer ringPlayer;

	private Vibrator vVibrator;
	private final static long[] vibratePattern = { 0, 1000, 1000 };

	private int nSDKVer;

	private static final HashMap<Character, Integer> toneMap = new HashMap<Character, Integer>();

	private static VoiceEngine voiceEngine = null;

	private VoiceConfig voiceConfig;

	private PowerManager.WakeLock pwLock;
	private WifiManager.WifiLock wwLock;

	public static synchronized VoiceEngine getInstance(Context ctx) {
		if (voiceEngine == null) {
			voiceEngine = new VoiceEngine(ctx);
		}
		return voiceEngine;
	}

	public static VoiceEngine getVoiceEngine() {
		return voiceEngine;
	}

	private VoiceEngine(Context ctx) {

		bStart = false;
		voiceConfig = VoiceConfig.getInstance(ctx);
		nSDKVer = Integer.parseInt(Build.VERSION.SDK);
		if (nSDKVer > 6) {
			if (gipsVoice == null) {
				gipsVoice = new GIPSVoice(ctx);
			}
			if (gipsVoice.initLib()) {
				voiceMode = VOICE_GIPS;
			}
			else {
				voiceMode = VOICE_SIMPLE;
			}
		}
		else {
			voiceMode = VOICE_SIMPLE;
		}

		audioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);

		toneGenerator = new ToneGenerator(AudioManager.STREAM_RING, audioManager.getStreamMaxVolume(AudioManager.STREAM_RING) * 8);

		toneMap.put('1', ToneGenerator.TONE_DTMF_1);
		toneMap.put('2', ToneGenerator.TONE_DTMF_2);
		toneMap.put('3', ToneGenerator.TONE_DTMF_3);
		toneMap.put('4', ToneGenerator.TONE_DTMF_4);
		toneMap.put('5', ToneGenerator.TONE_DTMF_5);
		toneMap.put('6', ToneGenerator.TONE_DTMF_6);
		toneMap.put('7', ToneGenerator.TONE_DTMF_7);
		toneMap.put('8', ToneGenerator.TONE_DTMF_8);
		toneMap.put('9', ToneGenerator.TONE_DTMF_9);
		toneMap.put('0', ToneGenerator.TONE_DTMF_0);
		toneMap.put('#', ToneGenerator.TONE_DTMF_P);
		toneMap.put('*', ToneGenerator.TONE_DTMF_S);
	}

	public void setContext(Context ctx) {
		voiceConfig.setContext(ctx);
	}

	public boolean init() {
		return true;
	}

	public boolean start(int localPort, String remoteAddr, int remotePort, Codecs.Map cm) {
		return start(localPort, remoteAddr, remotePort, cm, true);
	}

	public boolean start(int localPort, String remoteAddr, int remotePort, Codecs.Map cm, boolean playout) {
		synchronized (this) {

			wakeLock(true);

			if (playout)
				Log.v("VoiceEngine", "start(playout=true)");
			else
				Log.v("VoiceEngine", "start(playout=false)");

			if (bStart) {
				Log.v("VoiceEngine", "if (bStart) {...");
				if ((bPlayout == false) && playout) {
					if (voiceMode == VOICE_GIPS) {
						// maximizeVolume();
						// gipsVoice.setVolumeRaise(0.5);
						Log.v("VoiceEngine", "start:startPlayout");
						if (gipsVoice != null)
							gipsVoice.startPlayout();
					}
					bPlayout = true;
				}
				return true;
			}

			bPlayout = playout;

			if (voiceMode == VOICE_GIPS) {
				maximizeVolume();
				// gipsVoice.setVolumeRaise(0.5);
				Log.v("VoiceEngine", "before gipsVoice.start");
				gipsVoice.start(localPort, remoteAddr, remotePort, cm.codec.number(), playout);
				Log.v("VoiceEngine", "after gipsVoice.start");
			}
			else {
				Log.v("VoiceEngine", "before simpleVoice.startMedia();");
				if (simpleVoice == null) { // for testing..
					simpleVoice = new SimpleVoice(localPort, remoteAddr, remotePort, cm);
				}
				simpleVoice.startMedia();
				Log.v("VoiceEngine", "after simpleVoice.startMedia();");
			}

			if (VoiceConfig.LOG_ENABLE)
				Log.d("VoiceEngine", "start end");

			bStart = true;
			return true;
		}
	}

	public void stop() {
		// Added by huah in 2012-08-28

		synchronized (this) {

			wakeLock(false);
			if (VoiceConfig.LOG_ENABLE)
				Log.d("VoiceEngine", "stop...");
			if (bStart) {
				if (VoiceConfig.LOG_ENABLE)
					Log.d("VoiceEngine", "bStart,so stop! ");
				if (voiceMode == VOICE_GIPS) {
					// gipsVoice.setVolumeRaise(0.5);
					// gipsVoice.stop();
					new Thread() {
						@Override
						public void run() {
							gipsVoice.stop();
						}
					}.start();
					restoreVolume();
				}
				else {
					if (simpleVoice != null) {
						simpleVoice.stopMedia();
						simpleVoice = null;
					}
				}
			}
			bStart = false;
			adjustVolume = false;
		}
	}

	public void destroy() {

		wakeLock(false);

		if (voiceMode == VOICE_GIPS) {
			gipsVoice.terminate();
		}

	}

	public void reset() {

		adjustVolume = false;

		setSpeaker(false);
		setMute(false);

	}

	// 打开扬声器
	public void setSpeaker(boolean on) {

		if (voiceMode == VOICE_SIMPLE) {
			if (simpleVoice != null)
				simpleVoice.setSpeaker(on);
			if (SIPConfig.devMode.startsWith("ZTE")) {
				setAudioMode(!on);
			}
			else {
				// audioManager.setSpeakerphoneOn(on);
			}
		}
		else {

			SetPlayoutSpeaker(on);

		}

	}

	private int SetPlayoutSpeaker(boolean loudspeakerOn) {

		if (loudspeakerOn)
			gipsVoice.setVolumeRaise(8.0);
		else
			gipsVoice.setVolumeRaise(1.0);

		// String brand = Build.BRAND;
		// Log.d("openSpeaker:", "Brand is:" + brand);

		int apiLevel = Integer.parseInt(android.os.Build.VERSION.SDK);

		if ((3 == apiLevel) || (4 == apiLevel)) {
			// 1.5 and 1.6 devices
			if (loudspeakerOn) {
				// route audio to back speaker
				audioManager.setMode(AudioManager.MODE_NORMAL);
			}
			else {
				// route audio to earpiece
				audioManager.setMode(AudioManager.MODE_IN_CALL);
			}
		}
		else {
			// 2.x devices
			if ((android.os.Build.BRAND.equals("Samsung") || android.os.Build.BRAND.equals("samsung")) && ((5 == apiLevel) || (6 == apiLevel) || (7 == apiLevel))) {
				// Samsung 2.0, 2.0.1 and 2.1 devices
				if (loudspeakerOn) {
					// route audio to back speaker
					audioManager.setMode(AudioManager.MODE_IN_CALL);
					audioManager.setSpeakerphoneOn(loudspeakerOn);
				}
				else {
					// route audio to earpiece
					audioManager.setSpeakerphoneOn(loudspeakerOn);
					audioManager.setMode(AudioManager.MODE_NORMAL);
				}
			}
			else {
				// Non-Samsung and Samsung 2.2 and up devices
				audioManager.setSpeakerphoneOn(loudspeakerOn);
			}
		}

		return 0;
	}

	public String getToneFileName() {

		Context ctx = voiceConfig.getContext();
		File file = ctx.getCacheDir();
		String filePath = file.getAbsolutePath();
		String filename = filePath + "/ringback.wav";

		File f = new File(filename);
		if (!f.exists()) {
			AssetManager assetManager = ctx.getAssets();
			InputStream inputStream = null;
			try {
				inputStream = assetManager.open("ringback.wav");
				f.createNewFile();
				FileOutputStream out = new FileOutputStream(f);
				byte[] bytes = VoiceUtil.InputStreamToByte(inputStream);
				out.write(bytes);
				out.close();
			}
			catch (IOException e) {

				return "";
			}
		}

		return filename;
	}

	public void sendRingTone() {
		if (voiceMode == VOICE_GIPS) {
			String toneFile = getToneFileName();
			if (gipsVoice != null)
				gipsVoice.playTone(toneFile);
		}
	}

	public void stopSendRingTone() {
		if (voiceMode == VOICE_GIPS) {
			if (gipsVoice != null)
				gipsVoice.stopPlayTone();
		}
	}

	public void vibrator(boolean on) {
		if (vVibrator == null)
			vVibrator = (Vibrator) voiceConfig.getContext().getSystemService(Context.VIBRATOR_SERVICE);
		if(on)
		{
			if (Util.getBoolean(Util.CONFIG_CALL_OK_VIBRATE, false)) {
				vVibrator.vibrate(vibratePattern, -1);
			}
			else {
				return;
			}
		}
		else
		{
			if (Util.getBoolean(Util.CONFIG_DIAL_VIBRATE, false)) {
				vVibrator.vibrate(200);//vibrator.vibrate(vibratePattern, -1);
			}
			else {
				return;
			}
		}
//		if (on) {
//			vVibrator.vibrate(vibratePattern, -1);
//		}
//		else {
//			vVibrator.vibrate(50);
//		}
	}

	/*public void dialVibrator(boolean on) {
		if (PreferencesUtil.getDialVibrate() == false)
			return;

		vibrator(on);
	}*/

	/*public void callOKVibrator(boolean on) {
		if (PreferencesUtil.getCallOKVibrate() == false)
			return;

		vibrator(on);
	}*/

	/*public void playKeyTone(char key) {
		if (PreferencesUtil.getDialSound()) {
			if (toneGenerator != null) {
				toneGenerator.stopTone();
				toneGenerator.startTone(toneMap.get(key), 250);
			}
		}else {
			return;
		}
	}*/

	public void setMute(boolean enable) {
		if (voiceMode == VOICE_GIPS) {
			if (gipsVoice != null)
				gipsVoice.muteMic(enable);
		}
		else {
			if (simpleVoice != null)
				simpleVoice.muteMedia(enable);
		}

	}

	public void setAudioMode(boolean isCall) {

		if (voiceMode == VOICE_SIMPLE) {
			int audioMode = isCall ? AudioManager.MODE_IN_CALL : AudioManager.MODE_NORMAL;
			if (RTPStreamReceiver.audioMode == audioMode)
				return;
			RTPStreamReceiver.audioMode = audioMode;
			if (simpleVoice != null)
				simpleVoice.setMode(isCall);
		}

	}

	public void ringback(boolean ringback) {

		synchronized (this) {

			if (ringback && ringbackPlayer == null) {

				// TODO:
				RTPStreamReceiver.enableBluetooth(VoiceConfig.DEFAULT_BLUETOOTH);

				ringbackPlayer = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, (int) (ToneGenerator.MAX_VOLUME * 2 * VoiceConfig.getEarGain()));
				ringbackPlayer.startTone(ToneGenerator.TONE_SUP_RINGTONE);
			}
			else if (!ringback && ringbackPlayer != null) {
				ringbackPlayer.stopTone();
				ringbackPlayer.release();
				ringbackPlayer = null;
				if (SIPEngine.getSIPEngine().getCallState() == SIPEngine.CALLSTATE_IDLE) {

					RTPStreamReceiver.enableBluetooth(false);

				}
			}

		}

	}

	public void startRing() {

		Context ctx = voiceConfig.getContext();
		int rm = audioManager.getRingerMode();
		int vs = audioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);

		if (vVibrator == null)
			vVibrator = (Vibrator) ctx.getSystemService(Context.VIBRATOR_SERVICE);

		if ((rm == AudioManager.RINGER_MODE_VIBRATE || (rm == AudioManager.RINGER_MODE_NORMAL && vs == AudioManager.VIBRATE_SETTING_ON)))
			vVibrator.vibrate(vibratePattern, 1);

		if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {

			String sUriSipRingtone = Settings.System.DEFAULT_RINGTONE_URI.toString();
			if (!TextUtils.isEmpty(sUriSipRingtone)) {
				// oRingtone = RingtoneManager.getRingtone(this,
				// Uri.parse(sUriSipRingtone));
				//
				// if (oRingtone != null)
				// oRingtone.play();

				ringPlayer = new MediaPlayer();
				Uri alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);

				try {
					ringPlayer.setDataSource(ctx, alert);
				}
				catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

				ringPlayer.setAudioStreamType(AudioManager.STREAM_RING);
				ringPlayer.setLooping(true);
				try {
					ringPlayer.prepare();
					ringPlayer.start();
				}
				catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		}
	}

	public void stopRing() {

		if (vVibrator != null) {
			vVibrator.cancel();
			vVibrator = null;
		}
		// if (oRingtone != null) {
		// Ringtone ringtone = oRingtone;
		// oRingtone = null;
		// ringtone.stop();
		// }
		if (ringPlayer != null) {
			ringPlayer.stop();
			ringPlayer = null;
		}
	}

	public boolean adjustVolume(boolean up) {

		if (voiceMode != VOICE_GIPS)
			return false;

		adjustVolume = true;

		if (up) {
			audioManager.adjustStreamVolume(AudioManager.STREAM_VOICE_CALL, AudioManager.ADJUST_RAISE, AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_SHOW_UI);
		}
		else {
			audioManager.adjustStreamVolume(AudioManager.STREAM_VOICE_CALL, AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_SHOW_UI);
		}

		return true;
	}

	private void maximizeVolume() {

		nCurVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);

		audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0);
		// setStreamVolume(AudioManager.STREAM_MUSIC,
		// am.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 3 / 4, 0);
	}

	private void restoreVolume() {

		if (adjustVolume)
			return;

		if (nCurVolume != -1)
			audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, nCurVolume, 0);
		nCurVolume = -1;
	}

	public synchronized void wakeLock(boolean lock) {
		if (lock) {
			if (pwLock == null) {
				Context ctx = voiceConfig.getContext();
				PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
				WifiManager wm = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
				pwLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "uCaller.VoiceCore");
				pwLock.acquire();
				wwLock = wm.createWifiLock(3, "uCaller.VoiceCore");
				wwLock.setReferenceCounted(false);
				wwLock.acquire();
			}
		}
		else if (pwLock != null) {
			if (pwLock.isHeld())
				pwLock.release();
			pwLock = null;
			if (wwLock != null && wwLock.isHeld())
				wwLock.release();
			wwLock = null;
		}
	}
}
